package controler;
import controler.states.CreateRenderObject;
import controler.states.Initial;
import controler.states.MoveSelection;
import controler.states.MultipleSelection;
import controler.states.PhysicPointSimpleSelection;
import controler.states.PhysicShapeEdition;
import controler.states.SimpleSelection;
import model.LevelEditorModel;
import view.events.LevelEditorViewKeyboardEvent;
import view.events.LevelEditorViewMouseEvent;
import view.events.LevelEditorViewOtherEvent;
import view.LevelEditorView;

/**
 * @author Damien Mabin
 */

class LevelEditorControler 
{

	private var m_Model 				: LevelEditorModel;
	private var m_View 					: LevelEditorView;
	private var m_CurrentState 			: A_State;
	
	private var m_UserCommands			: Array<A_UserCommand>;
	private var m_NextCommandIndex		: Int;
	
	public  var m_KeyboardKeyState		: Array<Bool>;
	
	public var INITIAL					: A_State;
	public var SIMPLE_SELECTION			: A_State;
	public var MULTIPLE_SELECTION		: A_State;
	public var MOVE_SELECTION			: A_State;
	public var CREATE_RENDER_OBJECT		: A_State;
	public var PHYSIC_SHAPE_EDITION 	: A_State;
	public var PHX_PT_SIMPLE_SELECTION 	: A_State;
	
	public function new(_Model:LevelEditorModel, _View:LevelEditorView) 
	{
		m_Model = _Model;
		m_View = _View;
		A_State.s_Controller = this;
		A_State.s_Model = m_Model;
		A_State.s_View = m_View;
		A_UserCommand.s_Controler = this;
		A_UserCommand.s_Model = m_Model;
		m_UserCommands = new Array<A_UserCommand>();
		m_KeyboardKeyState = new Array<Bool>();
		m_NextCommandIndex = 0;
		
		INITIAL 				= new Initial();
		SIMPLE_SELECTION 		= new SimpleSelection();
		MULTIPLE_SELECTION 		= new MultipleSelection();
		MOVE_SELECTION 			= new MoveSelection();
		CREATE_RENDER_OBJECT 	= new CreateRenderObject();
		PHYSIC_SHAPE_EDITION	= new PhysicShapeEdition();
		PHX_PT_SIMPLE_SELECTION = new PhysicPointSimpleSelection();
		
		SetState(INITIAL);
		
		m_View.addEventListener(LevelEditorViewMouseEvent.EVENT, OnEditorMouseEvent);
		m_View.addEventListener(LevelEditorViewKeyboardEvent.EVENT, OnEditorKeyboardEvent);
		m_View.addEventListener(LevelEditorViewOtherEvent.EVENT, OnEditorOtherEvent);
	}
	
	public function GetState():A_State
	{
		return m_CurrentState;
	}
	
	public function SetState(_NewState:A_State):Void
	{
		#if debug
			trace("Controller change state : " + Type.getClassName(Type.getClass(m_CurrentState)) + " -> " + Type.getClassName(Type.getClass(_NewState)));
		#end
		m_CurrentState = _NewState;
	}
	
	public function DoUserCommand(_UserCommand:A_UserCommand):Void
	{
		_UserCommand.DoCommand();
		if (_UserCommand.m_CanBeUndo)
		{
			if (!_UserCommand.m_Stackable)
			{
				m_UserCommands[m_NextCommandIndex] = _UserCommand;
				m_NextCommandIndex++;
			}
			else
			{
				if (m_NextCommandIndex > 0)
				{
					m_UserCommands[m_NextCommandIndex - 1].AgregateUserCommand(_UserCommand);
				}
				else
				{
					m_UserCommands[m_NextCommandIndex] = _UserCommand;
					m_NextCommandIndex++;
				}
			}
		}
	}
	
	private function OnEditorOtherEvent(_Evt:LevelEditorViewOtherEvent):Void
	{
		m_CurrentState.dispatchEvent(_Evt);
	}
	
	private function OnEditorKeyboardEvent(_Evt:LevelEditorViewKeyboardEvent):Void
	{
		if (_Evt.m_Type == E_KeyboardInteractionType.KEY_UP)
		{
			m_KeyboardKeyState[_Evt.m_KeyCode] = false;
		}
		else
		{
			m_KeyboardKeyState[_Evt.m_KeyCode] = true;
		}
		
		if(_Evt.m_Type == KEY_DOWN && _Evt.m_KeyCode == 90/*keycode of the 'z' key*/ && m_KeyboardKeyState[17/*keycode of ctrl*/])
		{
			if (m_NextCommandIndex > 0)
			{
				m_NextCommandIndex--;
				// We undo and change current point in the action stack
				var command : A_UserCommand = m_UserCommands[m_NextCommandIndex];
				if (command != null)
				{
					command.UndoCommand();
				}
			}
		}
		else if(_Evt.m_Type == KEY_DOWN && _Evt.m_KeyCode == 89/*keycode of the 'y' key*/ && m_KeyboardKeyState[17/*keycode of ctrl*/])
		{
			if (m_NextCommandIndex < m_UserCommands.length)
			{
				// We undo and change current point in the action stack
				var command : A_UserCommand = m_UserCommands[m_NextCommandIndex];
				if (command != null)
				{
					command.DoCommand();
				}
				m_NextCommandIndex++;
			}
		}
		m_CurrentState.dispatchEvent(_Evt);
	}
	
	private function OnEditorMouseEvent(_Evt:LevelEditorViewMouseEvent):Void
	{
		m_CurrentState.dispatchEvent(_Evt);
	}
}